--[[------------------------------------------------------------------------------------------------ Helicopter movement Андрущенко Иван -- NOTE: Needs rewritten to track enemy by ID, reference is BAD! --------------------------------------------------------------------------------------------------]] local state_move = 0 ---------------------------------------------------------------------------------------------------- class "heli_move" function heli_move:__init( obj, storage ) self.object = obj local se_obj = alife_object(obj:id()) self.heliObject = obj:get_helicopter() self.a = storage self.st = db.storage[obj:id()] self.heli_fly = heli_fly.get_heli_flyer(obj) self.heli_fire = heli_fire.get_heli_firer(obj) self.heli_look = heli_look.get_heli_looker(obj) self.a.increment = 1 -- using alife simulation if (se_obj and se_obj.respawn_point_prop_section) then self.a.use_combat = true end end function heli_move:reset_scheme( loading ) --printf("heli_move: START reset_scheme: loading[%s] %s",loading,self.object:name()) self.a.signals = {} self.heliObject:TurnEngineSound(self.a.engine_sound and ui_options.get("alife/general/heli_engine_sound")) ----------------------------------Вейпоинты - Начало------------------------------------------------ if (self.a.path_move) then if not level.patrol_path_exists(self.a.path_move) then printf("heli_move: reset_scheme: Patrol path %s doesnt exist", self.a.path_move) return end self.patrol_move = patrol(self.a.path_move) self.patrol_move_info = utils_obj.path_parse_waypoints(self.a.path_move) else self.patrol_move = nil self.patrol_move_info = nil end if self.a.path_look then if self.a.path_look == "actor" then self.heli_fly:set_look_point(db.actor:position()) self:update_look_state() else self.patrol_look = patrol(self.a.path_look) self.heli_fly:set_look_point(self.patrol_look:point( 0 )) self:update_look_state() if not self.patrol_look then printf("object '%s': unable to find path_look '%s' on the map",self.object:name(), self.a.path_look) return end end else self.patrol_look = nil end self.max_velocity = self.a.max_velocity if loading then self.state = load_var(self.object, "st") self.last_index = load_var(self.object, "li") or nil self.next_index = load_var(self.object, "ni") or nil self.was_callback = load_var(self.object, "wc") self.a.path_index = load_var(self.object,"path_index") or 1 self.a.path_increment = load_var(self.object,"path_increment") or 1 else self.last_index = nil self.next_index = nil self.heli_fly.max_velocity = self.max_velocity self.heli_fly.heliLAccFW = self.max_velocity / 15 self.heli_fly.heliLAccBW = 2 * self.heli_fly.heliLAccFW / 3 self.heliObject:SetLinearAcc(self.heli_fly.heliLAccFW, self.heli_fly.heliLAccBW); self.heliObject:SetMaxVelocity( self.max_velocity ) self.state = nil self.stop_point = nil self.by_stop_fire_fly = false self.was_callback = false self._flag_to_wp_callback = false self.heli_fire.enemy_ = self.a.enemy_ self.heli_fire.enemy_id = nil self.heli_fire.flag_by_enemy = true if self.a.fire_point then local pat = patrol(self.a.fire_point) if (pat) then self.heli_fire.fire_point = pat:point(0) end end if self.a.max_mgun_dist then self.heliObject.m_max_mgun_dist = self.a.max_mgun_dist end if self.a.max_rocket_dist then self.heliObject.m_max_rocket_dist = self.a.max_rocket_dist end if self.a.min_mgun_dist then self.heliObject.m_min_mgun_dist = self.a.min_mgun_dist end if self.a.min_rocket_dist then self.heliObject.m_min_rocket_dist = self.a.min_rocket_dist end if self.a.use_mgun then self.heliObject.m_use_mgun_on_attack = true else self.heliObject.m_use_mgun_on_attack = false end if self.a.use_rocket then self.heliObject.m_use_rocket_on_attack = true else self.heliObject.m_use_rocket_on_attack = false end self.heli_fire.upd_vis = self.a.upd_vis if not (self.st.combat.enemy) then self.heli_fire:update_enemy_state() end self:update_movement_state() db.storage[self.object:id()].show_health = self.a.show_health self.heliObject:UseFireTrail(self.a.fire_trail) end --printf("heli_move: END reset_scheme: %s", self.object:name()) end function heli_move:save() save_var( self.object, "st", self.state ) ----------------------------------Вейпоинты - Начало------------------------------------------------ save_var( self.object, "li", self.last_index or false ) save_var( self.object, "ni", self.next_index or false ) ----------------------------------Вейпоинты - Конец------------------------------------------------- save_var( self.object, "wc", self.was_callback ) save_var( self.object, "path_index", self.a.path_index ) save_var( self.object, "path_increment", self.a.path_increment ) end function heli_move:update( delta ) if xr_logic.try_switch_to_another_section(self.object, self.a, db.actor) then return end if (self.st.combat.enemy_id) then return end self.heli_fire:update_enemy_state() if (self.a.path_move == nil or self.a.retreat_mode) then self:update_path_by_logic() end if self.was_callback then self:update_movement_state() self.was_callback = false end if self.a.path_look then if self.a.path_look == "actor" then self.heli_fly:set_look_point(db.actor:position()) if self.a.stop_fire then if self.heliObject:isVisible( db.actor ) then if not self.by_stop_fire_fly then self.stop_point = self.object:position() self.by_stop_fire_fly = true self.was_callback = true --'printf("Stop Fire!") end else --'printf("Fly to next point!") self.by_stop_fire_fly = false self.was_callback = true end end end self:update_look_state() end if not self.a.path_look and self.heli_look.look_state then self.heli_look:calc_look_point(self.heli_fly.dest_point, true) end end function heli_move:iterate_nodes() if not (self.a.nodes) then return end --printf("iterating nodes") if not (self.a.path_index) then self.a.path_index = 1 end if (self.object:position():distance_to_sqr(self.a.nodes[self.a.path_index].position) > 1.5) then self.heliObject:SetDestPosition(self.a.nodes[self.a.path_index].position) --printf("moving %s",self.a.path_index) return end if (self.a.nodes[self.a.path_index].delay and time_global() < self.a.nodes[self.a.path_index].delay) then --printf("delay %s",self.a.path_index) return end if (self.a.path_end) then if (self.a.increment < 0 and self.a.path_index == 1 or self.a.increment > 0 and self.a.path_index == #self.a.nodes) then local path_end = xr_logic.pick_section_from_condlist(db.actor, self.object, self.a.path_end) --printf("path_end %s %s",self.a.path_index,path_end) if (path_end == "loop") then self.a.path_index = 1 elseif (path_end == "reverse") then self.a.increment = -self.a.increment elseif (path_end and path_end ~= "nil") then xr_logic.switch_to_section(self.object, db.storage[self.object:id()].ini, path_end) end end end if (self.a.increment < 0 and self.a.path_index + self.a.increment >= 1 or self.a.increment > 0 and self.a.path_index + self.a.increment <= #self.a.nodes) then self.a.path_index = self.a.path_index + self.a.increment if (self.a.nodes[self.a.path_index].signal) then self.a.signals[self.a.nodes[self.a.path_index].signal] = true end --printf("increment %s",self.a.path_index) return end end function heli_move:create_path_nodes() if (self.a.nodes) then return end local st = db.storage[self.object:id()] local index = 1 local str = st.active_section and st.ini:r_string_ex(st.active_section,"pt"..tostring(index)) local p while (str and str ~= "" and str ~= "nil") do p = str_explode(str,",") if (p) then if not (self.a.nodes) then self.a.nodes = {} end if (p[1] and p[2] and p[3]) then self.a.nodes[index] = { position = vector():set(tonumber(p[1]),tonumber(p[2]),tonumber(p[3])) } end if (self.a.nodes[index]) then self.a.nodes[index].delay = p[4] and tonumber(p[4]) self.a.nodes[index].signal = p[5] end end index = index + 1 str = st.active_section and st.ini:r_string_ex(st.active_section,"pt"..tostring(index)) end end function heli_move:update_path_by_logic() if not (self.a.retreat_mode) then self:create_path_nodes() self:iterate_nodes() elseif (self.a.retreat_mode == 1) then self.heliObject:SetDestPosition(level.get_bounding_volume().max) elseif (self.a.retreat_mode == 2) then local pos = vector():set(level.get_bounding_volume().max.x,level.get_bounding_volume().min.y-50,level.get_bounding_volume().max.z) self.heliObject:SetDestPosition(pos) end end function heli_move:update_movement_state() --'printf("update_movement_state()") if not (self.patrol_move) then return end self.state = state_move if self.patrol_move then if not self.last_index then self.last_index = 0 self.next_index = 1 else self.next_index = self.last_index + 1 if self.next_index >= self.patrol_move:count() then self.next_index = 0 end end end if not self.by_stop_fire_fly then if self.patrol_move:count() > 2 then self._flag_to_wp_callback = self.heli_fly:fly_on_point_with_vector( self.patrol_move:point( self.last_index ), self.patrol_move:point( self.next_index ), self.max_velocity, self._flag_to_wp_callback, false) else if self.patrol_move:count() > 1 then self._flag_to_wp_callback = self.heli_fly:fly_on_point_with_vector( self.patrol_move:point( self.last_index ), self.patrol_move:point( self.next_index ), self.max_velocity, true, true) else self._flag_to_wp_callback = self.heli_fly:fly_on_point_with_vector( self.patrol_move:point( self.last_index ), self.patrol_move:point( self.last_index ), self.max_velocity, true, true) end end else self._flag_to_wp_callback = self.heli_fly:fly_on_point_with_vector( self.stop_point, self.stop_point, self.max_velocity, true, false) self._flag_to_wp_callback = true end end function heli_move:update_look_state() --' printf("update_look_state()") self.heli_fly:set_block_flook(true) self.heli_fly:look_at_position() end function heli_move:waypoint_callback( obj, action_type, index ) if (self.st.combat:waypoint_callback()) then return end ----------------------------------Вейпоинты - Начало------------------------------------------------ if not self._flag_to_wp_callback then --'printf("heli_pos=[%d;%d;%d]",self.object:position().x,self.object:position().y,self.object:position().z) --'printf("dist_to_dest_point=%d",self.heliObject:GetDistanceToDestPosition()) if self.patrol_move then if index == self.last_index then return end if index ~= -1 then self.last_index = index else --' Выдать коллбек if self.patrol_move_info[self.last_index] ~= nil then local signal = self.patrol_move_info[self.last_index]["sig"] if signal ~= nil then self.a.signals[signal] = true end end if self.patrol_move:count()>1 then self.last_index = self.next_index end end end end ----------------------------------Вейпоинты - Конец------------------------------------------------- --' printf("Dist To Dest Point: %s", self.heliObject:GetDistanceToDestPosition()) --' printf("heli_move:waypoint_callback(): name=%s, index=%d", self.object:name(), index) self.was_callback = true end --------------------------------------------------------------------------------------------------------------------- function add_to_binder( npc, ini, scheme, section, storage ) --printf( "DEBUG: add_to_binder: npc:name()='%s', scheme='%s', section='%s'", npc:name(), scheme, section ) local new_action = heli_move( npc, storage ) -- Зарегистрировать все actions, в которых должен быть вызван метод reset_scheme при изменении настроек схемы: xr_logic.subscribe_action_for_events( npc, storage, new_action ) end function set_scheme( npc, ini, scheme, section, gulag_name) local a = xr_logic.assign_storage_and_bind( npc, ini, scheme, section ) a.logic = xr_logic.cfg_get_switch_conditions( ini, section, npc ) local st = db.storage[npc:id()] a.retreat_mode = ini:r_float_ex(section,"retreat_mode") if not (retreat_mode) then a.path_move = utils_data.prefix_r_string(ini,section,"path_move",gulag_name) if not (a.path_move and level.patrol_path_exists(a.path_move)) then a.path_move = ini:r_string_ex(section,"path_move") if not (a.path_move and level.patrol_path_exists(a.path_move)) then printf("Patrol path %s doesnt exist", a.path_move) a.path_move = nil else a.path_look = ini:r_string_ex(section,"path_look") end else a.path_look = utils_data.prefix_r_string(ini,section,"path_look",gulag_name) end end --printf("heli_move %s",a.path_move) a.max_velocity = ini:r_float_ex(section,"max_velocity") or st.combat and st.combat.max_velocity or 45 a.enemy_ = ini:r_string_ex(section, "enemy") a.fire_point = ini:r_string_ex(section, "fire_point") a.max_mgun_dist = ini:r_float_ex(section,"max_mgun_attack_dist") or 0 a.max_rocket_dist = ini:r_float_ex(section,"max_rocket_attack_dist") or 0 a.min_mgun_dist = ini:r_float_ex(section,"min_mgun_attack_dist") or 0 a.min_rocket_dist = ini:r_float_ex(section,"min_rocket_attack_dist") or 0 a.use_rocket = ini:r_bool_ex(section, "use_rocket",st.combat and st.combat.combat_use_rocket or false) a.use_mgun = ini:r_bool_ex(section, "use_mgun",st.combat and st.combat.combat_use_mgun or false) a.engine_sound = ini:r_bool_ex(section, "engine_sound",false) a.upd_vis = ini:r_float_ex(section,"upd_vis") or 10 a.stop_fire = ini:r_bool_ex(section, "stop_fire",false) a.show_health = ini:r_bool_ex(section, "show_health",false) a.fire_trail = ini:r_bool_ex(section, "fire_trail",false) st.invulnerable = ini:r_bool_ex(section, "invulnerable",false) st.immortal = ini:r_bool_ex(section, "immortal",false) st.mute = ini:r_bool_ex(section, "mute",false) a.path_end = ini:r_string_to_condlist(section,"path_end") --st.combat:read_custom_data(ini,section) end